package com.sayice.gomoku.web;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sayice.gomoku.config.PlaySocketConfigurator;
import com.sayice.gomoku.game.Action;
import com.sayice.gomoku.game.Game;
import com.sayice.gomoku.pojo.MsgInfo;
import com.sayice.gomoku.pojo.Player;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * 处理对局请求
 */
@ServerEndpoint(value = "/play/{name}", configurator = PlaySocketConfigurator.class)
public class PlaySocket {
    /**
     * 玩家
     */
    private final Player player = new Player();
    
    @OnOpen
    public void onOpen(@PathParam("name") String name, Session session, EndpointConfig config) throws IOException {
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        Object id = httpSession.getAttribute(name);
        httpSession.removeAttribute(name);
        // 未登录时无法进入对战系统
        if (id == null) {
            session.getBasicRemote().sendText(new MsgInfo(Action.pleaseLogin, null).toJson());
            return;
        }
        player.online((int) id, name, session);
    }
    
    @OnClose
    public void onClose() throws IOException {
        player.offline();
    }
    
    @OnMessage
    public void onMessage(String msg) {
        JSONObject jsonObject = JSON.parseObject(msg);
        String action = jsonObject.getString("action");
        JSONObject params = jsonObject.getJSONObject("params");
        
        System.out.println("onMessage, action: " + action + ", params: " + params);
        
        try {
            // 根据 action 获取对应的业务方法反射对象
            Method method = this.getClass().getDeclaredMethod(action, JSONObject.class);
            method.invoke(this, params);
        } catch (Exception e) {
            e.printStackTrace();
            // 将异常抛给 Tomcat 管理
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 开始匹配
     *
     * @param params 参数（忽略）
     */
    private void startMatch(JSONObject params) throws IOException {
        player.startMatch();
    }
    
    /**
     * 发起挑战
     *
     * @param params 参数（目标玩家名）
     */
    private void sendChallenge(JSONObject params) throws IOException {
        String targetName = params.getString("targetName");
        Player targetPlayer = Game.playerMap.get(targetName);
        player.sendChallenge(targetPlayer);
    }
    
    /**
     * 处理挑战（接受/拒绝）
     *
     * @param params 参数（目标玩家名、是否接受）
     */
    private void handleChallenge(JSONObject params) throws IOException {
        String targetName = params.getString("targetName");
        boolean accept = params.getBoolean("accept");
        Player targetPlayer = Game.playerMap.get(targetName);
        player.handleChallenge(targetPlayer, accept);
    }
    
    /**
     * 下子
     *
     * @param params 参数（x坐标、y坐标）
     */
    private void playChess(JSONObject params) throws IOException {
        int x = params.getInteger("x");
        int y = params.getInteger("y");
        System.out.println(player.getName() + " try playChess(" + x + "," + y + ")");
        player.playChess(x, y);
    }
    
    /**
     * 请求悔棋
     *
     * @param params 参数（忽略）
     */
    private void sendUndo(JSONObject params) throws IOException {
        player.sendUndo();
    }
    
    /**
     * 处理悔棋请求（接受/拒绝）
     *
     * @param params 参数（是否接受）
     */
    private void handleUndo(JSONObject params) throws IOException {
        boolean accept = params.getBoolean("accept");
        player.handleUndo(accept);
    }
    
    /**
     * 查看最后一个棋子
     *
     * @param params 参数（忽略）
     */
    private void seeLastChess(JSONObject params) throws IOException {
        player.seeLastChess();
    }
    
    /**
     * 退出对局
     *
     * @param params 参数（忽略）
     */
    private void leaveGame(JSONObject params) throws IOException {
        player.leaveGame();
    }
    
    /**
     * 观战
     *
     * @param params 参数（房间号）
     */
    private void watchGame(JSONObject params) throws IOException {
        int roomId = params.getInteger("roomId");
        player.watchGame(roomId);
    }
    
    /**
     * 退出观战
     *
     * @param params 参数（忽略）
     */
    private void leaveWatch(JSONObject params) throws IOException {
        player.leaveWatch();
    }
    
    /**
     * 修复棋盘
     *
     * @param params 参数（忽略）
     */
    private void fixBoard(JSONObject params) throws IOException {
        player.sendRepaint();
    }
}
